<template>
    <div class="marquee-outer-div" ref="outerDiv">
        <div ref="innerDiv" :style="styleObject" class="inner-div">{{text}}</div>
    </div>
</template>

<script>
// 原本想用transition-duration来实现动画的，但是因为不会根据字符长度计算transition-duration的值，只能使用js来实现动画了

let animationFrameId = null;
export default {
    name: "MarqueeComponent",
    props: {
        text: {
            type: [String, Number]
        }
    },
    data() {
        return {
            styleObject: {
                transform: 'none'
            },
            outerDivWidth: 0,
            innerDivWidth: 0,
        };
    },
    watch: {
        text: {
            handler() {
                this.init();
            },
            immediate: true
        }
    },
    methods: {
        init() {
            this.$nextTick(() => {
                this.getAllDivWidth();
                this.setTranslateX();
                if (animationFrameId !== null) {
                    cancelAnimationFrame(animationFrameId);
                    animationFrameId = null;
                } else {
                    // 只有内部div超出外层div才开始滚动，否则会递归死循环
                    if (this.innerDivWidth > this.outerDivWidth) {
                        this.startAnimation();
                    }
                }
            });
        },
        startAnimation() {
            const that = this;
            let num = 0;

            function requestAnimationFn() {
                num += 1;
                const translateX = that.outerDivWidth - num;
                that.setTranslateX(`${translateX}px`);
                // 容易递归死循环的地方，如果页面刚开始内层div宽度小于外层div宽度，就会一直调用函数
                if (Math.abs(translateX) >= that.innerDivWidth) {
                    that.setTranslateX(`${that.outerDivWidth}px`);
                    num = 0;
                    requestAnimationFn();
                    return;
                }
                animationFrameId = requestAnimationFrame(requestAnimationFn);
            }

            requestAnimationFn();
        },
        setTranslateX(value) {
            let translateXValue = 'none';
            if (value) {
                translateXValue = `translateX(${value})`;
            }
            this.styleObject.transform = translateXValue;
        },
        getAllDivWidth() {
            const {outerDiv, innerDiv} = this.$refs;
            this.outerDivWidth = outerDiv.clientWidth;
            this.innerDivWidth = innerDiv.clientWidth;
            console.log("outerDivWidth: ", this.outerDivWidth);
            console.log("innerDivWidth: ", this.innerDivWidth);
        }
    }
}
</script>

<style scoped>
    .marquee-outer-div {
        overflow: hidden;
    }

    .inner-div {
        display: inline-block;
        white-space: nowrap;
    }
</style>
